package com.killer.sqlSession;

import com.killer.config.BoundSql;
import com.killer.pojo.Configuration;
import com.killer.pojo.MappedStatement;
import com.killer.utils.*;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor {
    @Override
    public <T> List<T> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        //这里开始执行jdbc代码逻辑
        //获取数据库连接
        Connection conn=configuration.getDataSource().getConnection();
        //需要获取解析后的sql 将#{var}替换成?占位符
        BoundSql boundSql = getBoundSql(mappedStatement.getSql());
        //获取preparedStament对象
        PreparedStatement preparedStatement = conn.prepareStatement(boundSql.getSql());
        //进行参数设置
        List<ParameterMapping> parameterMappingList=boundSql.getParameterMappingList();
        //获取参数类型
        Class<?> parameterType=mappedStatement.getParameterType();
        if(parameterType!=null){
            //判断参数类型是否是基本数据类型
            boolean isBaseType = TypeUtil.isBaseType(parameterType);
            for (int i = 0; i < parameterMappingList.size(); i++) {
                if (isBaseType) {
                    //如果是基本数据类型，直接set变量值就可以了  不用@Param的情况下，实际上也只能传一个参数
                    preparedStatement.setObject(i+1,params[i]);
                }else{
                    //如果不是基本数据类型,则需要获取对象对应的字段
                    //先获取变量名
                    String fieldName=parameterMappingList.get(i).getContent();
                    Field field = parameterType.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    preparedStatement.setObject(i+1,field.get(params[0]));
                }
            }
        }
        //执行sql语句
        ResultSet resultSet=preparedStatement.executeQuery();
        //进行结果集对象的封装
        Class<?> resultType=mappedStatement.getResultType();
        List<T> list = new ArrayList<T>();
        while (resultSet.next()) {
            //获取结果集元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            //创建结果集对象
            T t=(T)resultType.newInstance();
            //获取返回的字段数
            int columnCount=metaData.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                //获取字段名
                String columnName = metaData.getColumnName(i);
                //获取字段的值
                Object value = resultSet.getObject(columnName);
                try {
                    //创建属性描述器，为属性生成读写方法
                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultType);
                    Method writeMethod=propertyDescriptor.getWriteMethod();
                    //为对象的该属性赋值
                    writeMethod.invoke(t, value);
                } catch (Exception e) {
                    //有可能某些字段该对象并不拥有，因此这里捕获下异常继续封装下一个字段
                    continue;
                }
            }
            list.add(t);
        }
        return list;
    }

    @Override
    public int update(Configuration configuration, MappedStatement mappedStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //从configuration中获取数据库连接
        Connection conn=configuration.getDataSource().getConnection();
        //从mappedStatement中获取解析后的sql
        BoundSql boundSql = getBoundSql(mappedStatement.getSql());
        PreparedStatement preparedStatement = conn.prepareStatement(boundSql.getSql());
        //参数设置
        List<ParameterMapping> parameterMappingList=boundSql.getParameterMappingList();
        //获取参数类型
        Class<?> parameterType=mappedStatement.getParameterType();
        if (parameterType != null) {
            for (int i = 0; i < parameterMappingList.size(); i++) {
                if (TypeUtil.isBaseType(parameterType)) {
                    //基础类型或字符串直接设置
                    preparedStatement.setObject(i+1, params[i]);
                }else{
                    //对象类型则获取该对象对应字段的值
                    //字段名称
                    String fieldName=parameterMappingList.get(i).getContent();
                    Field field = parameterType.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    preparedStatement.setObject(i+1, field.get(params[0]));
                }
            }
        }
        //执行更新操作
        return preparedStatement.executeUpdate();
    }


    private BoundSql getBoundSql(String sql) {
        ParameterMappingTokenHandler handler=new ParameterMappingTokenHandler();
        GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
        //将sql进行解析，即占位符替换
        String sqlText=parser.parse(sql);
        return new BoundSql(sqlText, handler.getParameterMappings());
    }
}
